#ifndef CLOUDPROCESSDEPEND_H
#define CLOUDPROCESSDEPEND_H

#include <iostream>
#include <QObject>
#include <vector>
#include <pcl/common/common.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/filter.h>
#include <pcl/io/pcd_io.h>
#include <vtkPlaneSource.h>
#include <Eigen/Core>
#include <Eigen/Dense>
#include <pcl/common/transforms.h>
#include <pcl/keypoints/uniform_sampling.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/filters/project_inliers.h>
#include <pcl/features/normal_3d_omp.h> //使用OMP需要添加的头文件
#include <algorithm>
#include <limits>
#include <fstream>
#include <pcl/features/moment_of_inertia_estimation.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/radius_outlier_removal.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/surface/organized_fast_mesh.h>
#include <pcl/surface/concave_hull.h>
#include <pcl/surface/poisson.h>

typedef pcl::PointXYZ PointType;
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloudT;


#define X_Sort_direct 0;
#define Y_Sort_direct 1;


class CloudProcessDepend : public QObject
{
    Q_OBJECT
public:
    explicit CloudProcessDepend(QObject *parent = nullptr);

public:
    // 用于表示三维点的结构体
    struct Point3D {
        double x, y, z;

        Point3D(double x, double y, double z) : x(x), y(y), z(z) {}
        Point3D() : x(0), y(0), z(0) {}
    };

    // 表示向量方向
    struct Vector3D {
        float x, y, z;
    };

    // 用于表示三维点的位姿向量的结构体
    struct Pose_Vector {
        Eigen::Vector3f X_Vector;
        Eigen::Vector3f Y_Vector;
        Eigen::Vector3f Z_Vector;
    };

    struct InputsStruct {
        Eigen::MatrixXd data;		 // 结构体中的控制点数据
        Eigen::VectorXd x;			 // 参数化向量 x，它定义了曲线上点的位置
        std::vector<double> knots;	 // 结点向量
        int k;						 // 曲线的次数
        int ctrPnums;				 // 控制点的数量
        Eigen::VectorXd w;			 // 权重向量
    };

    struct PCAStructure
    {
        PointType centriod;
        PointType pcX;
        PointType pcY;
        PointType pcZ;
        Eigen::Matrix3f eigenVectorsPCA;
    };

    // 按照指定向量方向排序
    bool compareByDirection(Point3D a, Point3D b, Vector3D direction);
    float vector_module(Vector3D a);
    float point_product(Vector3D a, Vector3D b);

    bool compareByX(const Point3D& a, const Point3D& b);
    bool compareByY(const Point3D& a, const Point3D& b);

    void setCuttingNUM(int NUM){
        this->cutting_NUM = NUM;
    }

    void setCuttingDistance(float distance){
        this->cutting_distance = distance;
    }

    void setProjectThreshold(float threshold){
        this->project_threshold = threshold;
    }

    void setSortDirection(int direct){
        this->sort_direction = direct;
    }

    void setExtractPointsNUM(int NUM){
        this->extract_points_NUM = NUM;
    }

public:
    void InputCloud(pcl::PointCloud<pcl::PointXYZ>& input_cloud);

    /** 提取多个点云切片法向量方向坐标 **/
    void CuttingCloudPlanarSlices(std::vector<pcl::PointCloud<pcl::PointXYZ>>& extract_slices_NURBS,std::vector<pcl::PointCloud<pcl::PointXYZ>>& extract_slices_points,
                                                      std::vector<pcl::PointCloud<pcl::Normal>>& extrace_slices_NURBS_normals, std::vector<std::vector<Pose_Vector>>& extrace_slices_NURBS_direction_vectors);


    void CuttingCloudPlanarOnceSlice(std::vector<pcl::PointCloud<pcl::PointXYZ>>& extract_slices_NURBS,std::vector<pcl::PointCloud<pcl::PointXYZ>>& extract_slices_points,
                                                      std::vector<pcl::PointCloud<pcl::Normal>>& extrace_slices_NURBS_normals, std::vector<std::vector<Pose_Vector>>& extrace_slices_NURBS_direction_vectors);



    void CuttingCloudPlanarOnceSlice(std::vector<pcl::PointCloud<pcl::PointXYZ>>& extract_slices_NURBS,std::vector<pcl::PointCloud<pcl::PointXYZ>>& extract_slices_points,
                                                         std::vector<pcl::PointCloud<pcl::Normal>>& extrace_slices_NURBS_normals, std::vector<std::vector<Pose_Vector>>& extrace_slices_NURBS_direction_vectors, pcl::PointXYZ ref_point);

    /** 计算NURBS曲线点切线方向 **/
    void ComputeNURBSTangentdirection(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_NURBS, std::vector<Eigen::Vector3f>& cloud_NURBS_Tangentdirection);

    /** 滤波 **/
    void FilteringCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, float range, float Radius);

    /** 降采样 **/
    void DownsampleCloud(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, float LeafSize);

    /** 利用PCA主元分析法获得点云的三个主方向 **/
    CloudProcessDepend::PCAStructure GetPCADirection(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud);

    /** 计算点云平均点密度 **/
    float ComputeDensity(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud);

    /** 按距离切割点云 **/
    bool PlanarSegmentationByDistance(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_plane, pcl::ModelCoefficients coefficients, float distance_threshold);

    /** 计算点云法线 **/
    void ComputeNormals(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::Normal>::Ptr& normals);
    void normal_flip(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::Normal>::Ptr& cloud_normals, int seed_index);

    /** 沿法线方向提离高度 **/
    void NURBSExtendHeightByNormals(pcl::PointCloud<pcl::PointXYZ> NURBS_cloud, pcl::PointCloud<pcl::Normal>::Ptr& NURBS_normals, pcl::PointCloud<pcl::PointXYZ>::Ptr& extend_cloud, float height_increment);

    /** 贪婪投影三角化算法无序点云曲面重建 **/
    void DisorderedPointCloudsSurfaceRestruction(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PolygonMesh& triangles);

    /** 泊松重建 **/
    void PoissonSurfaceReconstruction(pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PolygonMesh& output_mesh);

    /** 生成NURBS曲线 **/
    bool GetNURBS(const std::vector<Point3D>& TargetPoints, std::vector<Point3D>& point3D, int k);
    double GetBasisFcn(double x, const std::vector<double>& knots, int i, int k);
    Eigen::MatrixXd MyNURBS(const InputsStruct& inputs);

signals:
    void Signal_SendMessage(QString message);

private:
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;				// 点云
    pcl::PointXYZ p_min, p_max;

    int cutting_NUM;
    int extract_points_NUM;
    float cutting_distance;
    float project_threshold;
    int sort_direction;
};

#endif // CLOUDPROCESSDEPEND_H
